#pragma once

#include "MySock.hpp"
#include <unistd.h>
#include <signal.h>
#include <functional>

namespace QiHai
{
    using func_t = std::function<void(void*)>;

    class TCPServerData
    {
    public:
        int _sock;
        std::string _ip;
        int16_t _port;

        TCPServerData(int sock, const std::string& ip, int16_t port):_sock(sock), _ip(ip), _port(port)
        {}
    };

    class TCPServer
    {
    public:
        TCPServer(int16_t port, func_t func) : _port(port), _listenSock(-1), _disSock(-1), _func(func)
        {
        }

        void init()
        {
            // 初始化操作
            // 首先申请套接字
            _listenSock = Sock::socket();
            if (_listenSock < 0)
                exit(1);

            // 和本机服务绑定，默认'0.0.0.0'ip，让服务器绑定任意ip接收多个ip发送的消息
            if (!Sock::bind(_listenSock, _port))
                exit(2);

            // 设置套接字为监听状态
            if (!Sock::listen(_listenSock))
                exit(3);
            logMessage(NORMAL, "TCPServer init suncess......");
        }

        void start()
        {
            std::string clientIp;
            int16_t clientPort;
            signal(SIGCHLD, SIG_IGN); // 应用层忽略子进程退出
            while (true)
            {
                // 先建立连接
                _disSock = Sock::accept(_listenSock, &clientIp, &clientPort);
                if (0 > _disSock)
                    continue;

                // test
                if (fork() == 0)
                {
                    // 子进程
                    close(_listenSock);
                    TCPServerData* data = new TCPServerData(_disSock, clientIp, clientPort);
                    _func(data);
                    delete data;
                    close(_disSock);
                    exit(0);
                }
                close(_disSock);
            }
        }

        ~TCPServer()
        {
            if (_listenSock > 0)
                close(_listenSock);
        }

    private:
        int16_t _port;
        int _listenSock; // 监听套接字
        int _disSock;    // 处理套接字
        func_t _func;  // 设置处理函数
    };
}